import { Vue } from './install';
import ModuleCollection from './module/module-collection';
import { forEachValue } from './utils';

function getState(store, path) {
  return path.reduce((state, current) => {
    return state[current];
  }, store.state);
}

/**
 * 
 * @param {*} store Store 实例
 * @param {*} path 模块路径
 * @param {*} module 模块
 */
function installModule(store, path, module, rootState) {

  const namespace = store.modules.getNamespaced(path);
  console.log('namespace', namespace)


  // 如果模块路径大于 0,存在子模块
  if (path.length > 0) {
    // 把子模块的 state 处理到 rootState 上
    const parent = path.slice(0, -1).reduce((memo, current) => {
      return memo[current];
    }, rootState);

    // 把子模块的 state 挂载到父模块，子模块的状态 state 会覆盖父模块的状态
    // parent[path[path.length - 1]] = module.state;

    // 很少有用户会动态注册模块
    // 如果用户通过 store 的实例调用 registerModule 动态注册模块需要通过 Vue.set 劫持，
    Vue.set(parent, path[path.length - 1], module.state);
  }

  module.forEachMutation((mutationKey, mutationValue) => {
    // console.log(store.mutations[mutationKey], mutationKey)
    store.mutations[namespace + mutationKey] = store.mutations[namespace + mutationKey] || [];
    // 保存用户的 mutations 的属性和值
    store.mutations[namespace + mutationKey].push((payload) => {
      // 用户调用时候会执行 mutations 属性的函数
      // mutationValue(module.state, payload);

      // 为了解决调用 replaceState不会更新视图，需要这样编写代码
      mutationValue(getState(store, path), payload);

      // 执行用户注册的插件的
      // store._subscribes.forEach(cb => cb && cb({ type: mutationKey }, rootState));

      // 为了解决调用 replaceState 不会更新视图，需要这样编写代码
      store._subscribes.forEach(cb => cb && cb({ type: mutationKey }, store.state));
    })
  });

  module.forEachAction((actionKey, actionValue) => {
    store.actions[namespace + actionKey] = store.actions[namespace + actionKey] || [];
    // 保存用户的 actions 的属性和值
    store.actions[namespace + actionKey].push((payload) => {
      // 用户调用时候会执行 actions 属性的函数
      actionValue(store, payload);
    })
  });

  module.forEachGetter((getterKey, getterValue) => {
    // 如果有重复的
    if (store.wrappergetters[namespace + getterKey]) return console.error(`[vuex] duplicate getter key: ${getterKey}`)
    store.wrappergetters[namespace + getterKey] = () => {
      // 用户调用时候会执行 getters 属性的函数
      // return getterValue(module.state);

      // 为了解决调用 replaceState 不会更新视图，需要这样编写代码
      return getterValue(getState(store, path));
    }
  });

  module.forEachChildren((childName, childValue) => {
    installModule(store, path.concat(childName), childValue, rootState);
  });

}

function resetVM(store, state) {

  const oldVm = store.vm;

  // 把 getters 挂载到Vue的 computed
  const computed = {};
  store.getters = {};
  forEachValue(store.wrappergetters, (getterKey, getterValue) => {
    // 把 getters 的相关属性作为计算属性处理，有缓存作用，防止多次取值时消耗性能。
    computed[getterKey] = () => {
      return getterValue.call(store, state);
    };

    // Vuex 的 getters 只有 get 没有 set
    Object.defineProperty(store.getters, getterKey, {
      get: () => store.vm[getterKey],
    });
  });

  store.vm = new Vue({
    data: {
      $$state: state
    },
    computed
  });

  if (oldVm) {
    console.log('由于通过 store 的实例调用 regietorModule 动态注册，需要在这里销毁之前的 vm 实例');
    Vue.nextTick(() => oldVm.$destroy());
  }
}

class Store {
  constructor(options) {
    // console.log(options);
    // 转换用户传递属性格式
    this.modules = new ModuleCollection(options);
    console.dir(this.modules)

    this.actions = {}; // 存放所有模块 actions
    this.mutations = {}; // 存放所有模块 mutations

    this.wrappergetters = {}; // 所有的计算属性,多模块的话，如果不设置命名空间 namespaced: true,，会报报错：[vuex] duplicate getter key: xxx

    const rootState = options.state;

    this._subscribes = [];

    installModule(this, [], this.modules.root, rootState);
    console.log("mutations", this.mutations)
    console.log("actions", this.actions)
    console.log("state", rootState)

    resetVM(this, rootState);
    // 用户传递了插件，一个数组形式
    if (options.plugins) {
      options.plugins.forEach(plugin => plugin(this));
    }
  }

  // commit 挂载到 $store 上供用户调用， $store.commit("xxx", payload)
  commit = (mutationKey, payload) => {
    const mutations = this.mutations[mutationKey];
    mutations && mutations.forEach(mutation => mutation(payload));
  }

  // dispatch 挂载到 $store 上供用户调用， $store.dispatch("xxx", payload)
  dispatch = (actionKey, payload) => {
    const actions = this.actions[actionKey];
    actions && actions.forEach(action => action(payload))
  }

  get state() {
    return this.vm._data.$$state;
  }

  // 通过 Store 实例调用 registerModule 方法，动态创建模块 
  registerModule(path, rawModule) {
    if (!Array.isArray(path)) path = [path];

    // 注册模块
    this.modules.register(path, rawModule);
    // 安装模块
    installModule(this, path, rawModule.wrapperModule, this.state);

    // 保证 getters 也是响应式的
    resetVM(this, this.state);
  }

  // 数据变化就会自动调用该函数
  subscribe(cb) {
    cb && this._subscribes.push(cb);
  }
  // 替换当前状态
  replaceState(newState) {
    this.vm._data.$$state = newState;
  }
}


// class Store {
//   constructor(options) {
//     console.log(options)
//     // 用户的 state
//     const state = options.state;

//     this.getters = {};
//     // 用户的 getters
//     const getters = options.getters;
//     // 把 getters 放在 state 上不友好，每取一次就执行一次，消耗性能，因此，把 getter 定义到 compunted 来处理，他有缓存作用
//     // forEach(getters, (getterKey, getterValue) => {
//     //   Object.defineProperty(this.getters, getterKey, {
//     //     get: () => {
//     //       return getterValue.call(this, this.state);
//     //     }
//     //   });
//     // });
//     const computed = {};
//     forEach(getters, (getterKey, getterValue) => {
//       // 把 getters 的相关属性作为计算属性处理，有缓存作用，防止多次取值时消耗性能。
//       computed[getterKey] = () => {
//         return getterValue.call(this, this.state);
//       };

//       Object.defineProperty(this.getters, getterKey, {
//         get: () => this.vm[getterKey],
//       });
//     });


//     this.vm = new Vue({
//       data: {
//         $$state: state  // vue 内部处理了 $不被代理所以 使用 $$
//       },
//       computed
//     });

//     this.mutations = {};
//     // 用户的 mutations
//     const mutations = options.mutations;
//     forEach(mutations, (mutationKey, mutationValue) => {
//       this.mutations[mutationKey] = (payload) => mutationValue(this.state, payload);
//     });

//     this.actions = {};
//     // 用户的 mutations
//     const actions = options.actions;
//     forEach(actions, (actionKey, actionValue) => {
//       this.actions[actionKey] = (payload) => actionValue(this, payload);
//     });

//   }

//   // commit 挂载到 $store 上供用户调用， $store.commit("xxx", payload)
//   commit = (mutationKey, payload) => {
//     this.mutations[mutationKey](payload);
//   }

//   // dispatch 挂载到 $store 上供用户调用， $store.dispatch("xxx", payload)
//   dispatch = (actionKey, payload) => {
//     this.actions[actionKey](payload);
//   }

//   get state() {
//     // 通过中间层获取用户的 state
//     return this.vm._data.$$state;
//   }

// }

export default Store;